package cn.jb698.codec.msm.generator.util;

import java.sql.Types;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.jb698.codec.msm.generator.v5base.beans.BcrudCfgColumnObj;
import cn.jb698.codec.msm.generator.v5base.beans.BcrudCfgTableObj;

/**
 * JsBean字段属性专用工具类
 * @author Administrator(LiuJianbin)
 * @date 2021-01-28
 */
public class CodecCfgObjUtils {

	private static final Logger logger = LoggerFactory.getLogger(CodecCfgObjUtils.class);
	

	public static String columnTypeName_BIT = "BIT";
	public static String columnTypeName_TINYINT = "TINYINT";
	public static String columnTypeName_SMALLINT = "SMALLINT";
	public static String columnTypeName_INTEGER = "INTEGER";
	public static String columnTypeName_INT = "INT";
	public static String columnTypeName_BIGINT = "BIGINT";
	public static String columnTypeName_DECIMAL = "DECIMAL";
	public static String columnTypeName_DOUBLE = "DOUBLE";
	public static String columnTypeName_FLOAT = "FLOAT";
	public static String columnTypeName_REAL = "REAL";
	public static String columnTypeName_DATE = "DATE";
	public static String columnTypeName_TIME = "TIME";
	public static String columnTypeName_TIMESTAMP = "TIMESTAMP";
	public static String columnTypeName_DATETIME = "DATETIME";
	public static String columnTypeName_VARCHAR = "VARCHAR";
	public static String columnTypeName_CHAR = "CHAR";
    public static String columnTypeName_JSON = "JSON";
    public static String columnTypeName_TEXT = "TEXT";

	public static String jdbcType_INTEGER = "INTEGER";
	public static String jdbcType_DECIMAL = "DECIMAL";
	public static String jdbcType_VARCHAR = "VARCHAR";
	public static String jdbcType_DATE = "DATE";
	public static String jdbcType_TIMESTAMP = "TIMESTAMP";

	public static String javaType_Integer = "Integer";
	public static String javaType_String = "String";
	public static String javaType_Long = "Long";
	public static String javaType_Double = "Double";
	
	public static String javaType_BigDecimal = "BigDecimal";
	public static String javaType_Date = "Date";
	
	public static String golangType_Long = "int64";
	public static String golangType_Integer = "int";
	public static String golangType_String = "string";
	public static String golangType_Double = "float64";
	public static String golangType_Date = "time.Time";


//	/**
//	 * 默认的时间类型
//	 */
//	public static String dft_javaType_Time = javaType_Date;
//
//	/**
//	 * 默认的浮点数字类型
//	 */
//	public static String dft_javaType_Double = javaType_Double;
	
	/**
	 * 根据字段类型补充并计算字段信息,jdbcType,columnType,javaType,golangType等
	 * 
	 * @param columnJsBean
	 * @param columnType
	 * @param tableCfg 表级别配置
	 */
	public static void doColumnTypeCalcAndFill(BcrudCfgColumnObj columnJsBean, Integer columnType, BcrudCfgTableObj tableCfg) {
		String jdbcType = null;
		String javaType = null;
		String golangType = null; // golang的类型 
		String columnTypeStr = null;
		if (Types.BIT == columnType || Types.TINYINT == columnType || Types.INTEGER == columnType || Types.SMALLINT == columnType) {
			if (Types.BIT == columnType) {
				columnTypeStr = columnTypeName_BIT;
			} else if (Types.TINYINT == columnType) {
				columnTypeStr = columnTypeName_TINYINT;
			} else if (Types.INTEGER == columnType) {
				columnTypeStr = columnTypeName_INTEGER;
			} else if (Types.SMALLINT == columnType) {
				columnTypeStr = columnTypeName_SMALLINT;
			}

			jdbcType = jdbcType_INTEGER;
			javaType = javaType_Integer;
			golangType = golangType_Integer;
			
		} else if (Types.BIGINT == columnType) {
			if (Types.BIGINT == columnType) {
				columnTypeStr = columnTypeName_BIGINT;
			}
			jdbcType = jdbcType_INTEGER;
			javaType = javaType_Long;
			golangType = golangType_Long;
			
		} else if (Types.DECIMAL == columnType || Types.DOUBLE == columnType || Types.FLOAT == columnType || Types.REAL == columnType) {
			if (Types.DECIMAL == columnType) {
				columnTypeStr = columnTypeName_DECIMAL;
			} else if (Types.DOUBLE == columnType) {
				columnTypeStr = columnTypeName_DOUBLE;
			} else if (Types.FLOAT == columnType) {
				columnTypeStr = columnTypeName_FLOAT;
			} else if (Types.REAL == columnType) {
				columnTypeStr = columnTypeName_REAL;
			}
			jdbcType = jdbcType_DECIMAL;
			
			javaType = javaType_Double;

			String cfg_javaTypeDouble = tableCfg != null ? tableCfg.getJavaTypeDouble():null;
			if(cfg_javaTypeDouble != null && CodecCfgObjUtils.javaType_BigDecimal.equals(cfg_javaTypeDouble) ) {
				javaType = CodecCfgObjUtils.javaType_BigDecimal;
			}
			golangType = golangType_Double;
		} else if (Types.DATE == columnType || Types.TIME == columnType || Types.TIMESTAMP == columnType) {
			if (Types.DATE == columnType) {
				columnTypeStr = columnTypeName_DATE;
				jdbcType = jdbcType_DATE;
			} else if (Types.TIME == columnType) {
				columnTypeStr = columnTypeName_TIME;
				jdbcType = jdbcType_TIMESTAMP;
			} else if (Types.TIMESTAMP == columnType) {
				columnTypeStr = columnTypeName_TIMESTAMP;
				jdbcType = jdbcType_TIMESTAMP;
			}else {
				jdbcType = jdbcType_TIMESTAMP;
			}
			javaType = javaType_Date;
			golangType = golangType_Date;
		} else {
			// 默认为字符串
			columnTypeStr = columnTypeName_VARCHAR;
			jdbcType = jdbcType_VARCHAR;
			javaType = javaType_String;
			golangType = golangType_String;
		}
		logger.debug("columnType(" + columnType + ")转化值:columnTypeStr("+columnTypeStr+"),jdbcType(" + jdbcType + ")"+",javaType(" + javaType + "),golangType("+golangType+")" );
		columnJsBean.setColumnType(columnTypeStr);
		columnJsBean.setJdbcType(jdbcType);
		columnJsBean.setJavaType(javaType);
		columnJsBean.setGolangType(golangType);
	}

	/**
	 * 计算字段类型表达式
	 * @param columnJsBean jsBean
	 * @param columnTypeName
	 * @param displaySize
	 * @param precision
	 * @return
	 */
	public static String doColumnTypeExpressCalcAndFill(BcrudCfgColumnObj columnJsBean, String columnTypeName, Long displaySize, Integer precision) {
		String columnTypeExp = null ;
		if (columnTypeName_BIT.equalsIgnoreCase(columnTypeName) 
				|| columnTypeName_BIT.equalsIgnoreCase(columnTypeName) 
				|| columnTypeName_TINYINT.equalsIgnoreCase(columnTypeName)
		        || columnTypeName_INTEGER.equalsIgnoreCase(columnTypeName) 
		        || columnTypeName_SMALLINT.equalsIgnoreCase(columnTypeName) 
		        || columnTypeName_INT.equalsIgnoreCase(columnTypeName)
		        || columnTypeName_BIGINT.equalsIgnoreCase(columnTypeName)
		        || columnTypeName_CHAR.equalsIgnoreCase(columnTypeName)
		        || columnTypeName_VARCHAR.equalsIgnoreCase(columnTypeName)
				) {
			if(displaySize != null ) {
				columnTypeExp = columnTypeName + "(" + displaySize + ")"; // INT(10)
			}
		}else if (
				columnTypeName_DECIMAL.equalsIgnoreCase(columnTypeName)
				|| columnTypeName_DOUBLE.equalsIgnoreCase(columnTypeName)
				|| columnTypeName_FLOAT.equalsIgnoreCase(columnTypeName)
				|| columnTypeName_REAL.equalsIgnoreCase(columnTypeName)
				) {
			if(displaySize != null && precision != null ) {
				columnTypeExp = columnTypeName + "(" + precision + ","+(displaySize-precision) +")"; // DECIMAL(10,2)
			}
		}else {
			columnTypeExp = columnTypeName; 
		}
		if(columnTypeExp == null ) {
			columnTypeExp = columnTypeName; 
		}
		if(columnJsBean != null ) {
			columnJsBean.setColumnTypeExp(columnTypeExp);
		}
		return columnTypeExp ;
	}
	
	
	/**
	 * 解析注释用于给Velocity字符串显示
	 * @param comment
	 * @return
	 */
	public static String parseCommentForStr(String comment) {
		String rtStr = comment ;
		rtStr = rtStr.replaceAll("\\\\", "\\\\\\\\");
		rtStr = rtStr.replaceAll("\"", "\\\\\"");
		rtStr = rtStr.replaceAll("\n", "\\\\\n");
		return rtStr ;
	}

	/**
	 * 解析注释用于给代码注释显示
	 * @param comment
	 * @return
	 */
	public static String parseCommentForComment(String comment) {
		String rtStr = comment ;
		rtStr = rtStr.replaceAll("[*]/", "\\* /");
		return rtStr ;
	}
	

	/**
	 * 需要引入的Java类计算
	 * @param javaTypeSimpleName
	 * @return
	 */
	public static String doImportJavaTypeCalc(String javaTypeSimpleName) {
		String calcJavaType = null;
		if("Date".equals( javaTypeSimpleName)  ){
			calcJavaType = "java.util.Date";
		}else if( "LocalTime".equals( javaTypeSimpleName) ){
			calcJavaType = "java.time.LocalTime";
		}else if("LocalDate".equals( javaTypeSimpleName) ){
			calcJavaType = "java.time.LocalDate";
		}else if("LocalDateTime".equals( javaTypeSimpleName) ){
			calcJavaType = "java.time.LocalDateTime";
		}else if("LocalDateTime".equals( javaTypeSimpleName) ){
			calcJavaType = "java.time.LocalDateTime";
		}else if("BigDecimal".equals( javaTypeSimpleName) ){
			calcJavaType = "java.math.BigDecimal";
		}
		return calcJavaType;
	}

	/**
	 * 所有字段的Java类列表计算(并去重)
	 * @param cfgTableObj
	 * @return
	 */
	public static List<String> doColumnJavaTypeListCalc(BcrudCfgTableObj cfgTableObj) {
		List<String> calc_columnJavaTypeList = new ArrayList<>();
		for(BcrudCfgColumnObj tmpColumnBean : cfgTableObj.getPkColumns() ){
			String tmp_javaType = tmpColumnBean.getJavaType();
			String calcJavaType = doImportJavaTypeCalc(tmp_javaType);
			if(calcJavaType != null ) {
				calc_columnJavaTypeList.add(calcJavaType);
			}
		}
		for(BcrudCfgColumnObj tmpColumnBean : cfgTableObj.getOtherColumns() ){
			String tmp_javaType = tmpColumnBean.getJavaType();
			String calcJavaType = doImportJavaTypeCalc(tmp_javaType);
			if(calcJavaType != null ) {
				calc_columnJavaTypeList.add(calcJavaType);
			}
		}
		if(!calc_columnJavaTypeList.isEmpty()) {
			// 去重+排序 
			calc_columnJavaTypeList = calc_columnJavaTypeList.stream().filter(Objects::nonNull).distinct().sorted().collect(Collectors.toList());
		}
		return calc_columnJavaTypeList;
	}


	/**
	 * Model层的Import的列表计算
	 * @param cfgTableObj
	 * @return
	 */
	public static List<String> doModelImportListCalc(BcrudCfgTableObj cfgTableObj) {
	    List<String> totalImportJavaTypeList = new ArrayList<>();
	    for(BcrudCfgColumnObj tmpColumnBean : cfgTableObj.getPkColumns() ){
	        String tmp_javaType = tmpColumnBean.getJavaType();
	        String calcJavaType = doImportJavaTypeCalc(tmp_javaType);
	        if(calcJavaType != null ) {
	            totalImportJavaTypeList.add(calcJavaType);
	        }
	    }
	    for(BcrudCfgColumnObj tmpColumnBean : cfgTableObj.getOtherColumns() ){
	        String tmp_javaType = tmpColumnBean.getJavaType();
	        String calcJavaType = doImportJavaTypeCalc(tmp_javaType);
	        if(calcJavaType != null ) {
	            totalImportJavaTypeList.add(calcJavaType);
	        }
	    }

	    // 有带Map生成
	    totalImportJavaTypeList.add("java.io.Serializable");
	    totalImportJavaTypeList.add("java.util.HashMap");
	    totalImportJavaTypeList.add("java.util.Map");
	    
	    // hasBaomidou
	    if(cfgTableObj.getHasBaomidou()) {	        
	        totalImportJavaTypeList.add("com.baomidou.mybatisplus.annotation.IdType");
	        totalImportJavaTypeList.add("com.baomidou.mybatisplus.annotation.TableField");
	        totalImportJavaTypeList.add("com.baomidou.mybatisplus.annotation.TableId");
	        totalImportJavaTypeList.add("com.baomidou.mybatisplus.annotation.TableName");
	    }

        // hasPersistence
        if(cfgTableObj.getHasPersistence()) {
            totalImportJavaTypeList.add("javax.persistence.Column");
            totalImportJavaTypeList.add("javax.persistence.GeneratedValue");
            totalImportJavaTypeList.add("javax.persistence.GenerationType");
            totalImportJavaTypeList.add("javax.persistence.Id");
            totalImportJavaTypeList.add("javax.persistence.Table");
        }

	    // hasSwaggerUi
	    if(cfgTableObj.getHasSwaggerUi()) {
	        totalImportJavaTypeList.add("io.swagger.annotations.ApiModel");
	        totalImportJavaTypeList.add("io.swagger.annotations.ApiModelProperty");
	    }
	    if(!totalImportJavaTypeList.isEmpty()) {
	        // 去重+排序 
	        totalImportJavaTypeList = totalImportJavaTypeList.stream().distinct().filter(Objects::nonNull).sorted().collect(Collectors.toList());
	    }
	    
	    totalImportJavaTypeList = doCalcImportList(totalImportJavaTypeList,cfgTableObj);
        return totalImportJavaTypeList;

//	    List<String> importRuleList = cfgTableObj.getImportRuleList();
//	    if(Objects.isNull(importRuleList) || importRuleList.isEmpty() ) {
//	        importRuleList = doImportRuleListGet();
//	    }
//
//	    List<String> calcImportRuleList  = new ArrayList<>();
//	    Set<String> calcImportRuleHashSet = new HashSet<>();
//
//	    for (String tmpRule : importRuleList) {
//	        String calcRulePre = tmpRule.substring(0,tmpRule.length()-1);
//	        List<String> tmpMatchRuleList = totalImportJavaTypeList.stream().filter(obj->obj.startsWith(calcRulePre)).collect(Collectors.toList());
//	        if(tmpMatchRuleList != null && !tmpMatchRuleList.isEmpty() ) {
//	            tmpMatchRuleList = tmpMatchRuleList.stream().sorted().collect(Collectors.toList()); // 排序
//	            if(!calcImportRuleList.isEmpty()) {
//	                calcImportRuleList.add(""); // 非空的话,则在前面添加一个
//	            }
//	            calcImportRuleList.addAll(tmpMatchRuleList);
//	            calcImportRuleHashSet.addAll(tmpMatchRuleList);
//	        }
//        }
//
//	    // 计算规则之外的数据
//	    List<String> notInRuleClassList = totalImportJavaTypeList.stream().filter(obj->!calcImportRuleHashSet.contains(obj)).collect(Collectors.toList());
//	    if(notInRuleClassList != null && !notInRuleClassList.isEmpty() ) {
//	        notInRuleClassList = notInRuleClassList.stream().sorted().collect(Collectors.toList()); // 排序
//	        if(!calcImportRuleList.isEmpty()) {
//                calcImportRuleList.add(""); // 非空的话,则在前面添加一个
//            }
//	        calcImportRuleList.addAll(notInRuleClassList);
//            calcImportRuleHashSet.addAll(notInRuleClassList);
//	    }
	}

	/**
	 * Mapper层的Import的列表计算
	 * @param cfgTableObj
	 * @return
	 */
	public static List<String> doMapperImportListCalc(BcrudCfgTableObj cfgTableObj) {
	    List<String> totalImportJavaTypeList = new ArrayList<>();
	    
	    totalImportJavaTypeList.add("java.util.Collection");

	    // 自己的Model
	    String modelJavaType = cfgTableObj.getFileObjEntity().getObjFullName();
	    totalImportJavaTypeList.add(modelJavaType);

	    // ibatis 
	    totalImportJavaTypeList.add("org.apache.ibatis.annotations.Insert");
	    totalImportJavaTypeList.add("org.apache.ibatis.annotations.Mapper");
	    totalImportJavaTypeList.add("org.apache.ibatis.annotations.Options");
	    totalImportJavaTypeList.add("org.apache.ibatis.annotations.Param");
	    totalImportJavaTypeList.add("org.apache.ibatis.annotations.Update");
	    
	    // hasBaomidou
        if(cfgTableObj.getHasBaomidou()) {          
            // mybatisplus
            totalImportJavaTypeList.add("com.baomidou.mybatisplus.core.mapper.BaseMapper");
        }
	    
	    List<String> calcImportRuleList = doCalcImportList(totalImportJavaTypeList, cfgTableObj);

	    return calcImportRuleList;
	}

	
    
	/**
	 * 默认规则
	 * @return
	 */
    public static List<String> doDefaultImportRuleListGet(){
        List<String> importRuleList = new ArrayList<>();

        importRuleList.add("java.*");
        importRuleList.add("javax.*");
        importRuleList.add("org.*");
        importRuleList.add("com.*");

        return importRuleList ;
    }
    
	/**
	 * 计算Import列表
	 * @param rtImportList
	 * @param cfgTableObj
	 * @return
	 */
    public static List<String> doCalcImportList(List<String> totalImportList, BcrudCfgTableObj cfgTableObj) {
        
        if(Objects.isNull(totalImportList)) {
            return null;
        }
        if(totalImportList.isEmpty()) {
            return totalImportList;
        }

        List<String> rtImportList = totalImportList; 

	    // 去重+排序 
	    rtImportList = rtImportList.stream().distinct().filter(Objects::nonNull).sorted().collect(Collectors.toList());

	    List<String> importRuleList = cfgTableObj.getImportRuleList(); // 规则
	    if(Objects.isNull(importRuleList) || importRuleList.isEmpty() ) {
	        importRuleList = doDefaultImportRuleListGet();
	    }

	    List<String> calcImportRuleList  = new ArrayList<>();
	    Set<String> calcImportRuleHashSet = new HashSet<>();
	    
	    for (String tmpRule : importRuleList) {
	        String calcRulePre = tmpRule.substring(0,tmpRule.length()-1);
	        List<String> tmpMatchRuleList = rtImportList.stream().filter(obj->obj.startsWith(calcRulePre)).collect(Collectors.toList());
	        if(tmpMatchRuleList != null && !tmpMatchRuleList.isEmpty() ) {
	            tmpMatchRuleList = tmpMatchRuleList.stream().sorted().collect(Collectors.toList()); // 排序
	            if(!calcImportRuleList.isEmpty()) {
	                calcImportRuleList.add(""); // 非空的话,则在前面添加一个
	            }
	            calcImportRuleList.addAll(tmpMatchRuleList);
	            calcImportRuleHashSet.addAll(tmpMatchRuleList);
	        }
	    }
	    
	    // 计算规则之外的数据
	    List<String> notInRuleClassList = rtImportList.stream().filter(obj->!calcImportRuleHashSet.contains(obj)).collect(Collectors.toList());
	    if(notInRuleClassList != null && !notInRuleClassList.isEmpty() ) {
	        notInRuleClassList = notInRuleClassList.stream().sorted().collect(Collectors.toList()); // 排序
	        if(!calcImportRuleList.isEmpty()) {
	            calcImportRuleList.add(""); // 非空的话,则在前面添加一个
	        }
	        calcImportRuleList.addAll(notInRuleClassList);
	        calcImportRuleHashSet.addAll(notInRuleClassList);
	    }
        return calcImportRuleList;
    }

//	public static void main(String[] args) {
//		String str = "aabbccddee*/";
//		String parsedComment = parseCommentForComment(str);
//		System.err.println(parsedComment);
//	}
	
}
